﻿using System.Windows;
using System.Windows.Data;
using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit;
using Microsoft.Samples.Kinect.WpfViewers;
using Fizbin.Kinect.Gestures;
using System.Diagnostics;
using System.ComponentModel;
using System;
using System.Timers;
using System.IO;
using System.Reflection;

namespace GestureControlledTV
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {

        static int MaxChannel = 13;
        static int VolumeIncrement = 12;
        static int AutoTimeDelay = 15;
 

        static Uri[] Files = new Uri[MaxChannel];
        static string[] ShortDescriptions = new string[MaxChannel];
        private void initializeFiles()
        {


            string appPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location);

            appPath += "\\..\\..\\Resources\\clips\\";

            Files[0] = new Uri(appPath + "file01.avi");
            Files[1] = new Uri(appPath + "file02.avi");
            Files[2] = new Uri(appPath + "file03.avi");
            Files[3] = new Uri(appPath + "file04.avi");
            Files[4] = new Uri(appPath + "file05.avi");
            Files[5] = new Uri(appPath + "file06.avi");
            Files[6] = new Uri(appPath + "file07.avi");
            Files[7] = new Uri(appPath + "file08.avi");
            Files[8] = new Uri(appPath + "file09.avi");
            Files[9] = new Uri(appPath + "file10.avi");
            Files[10] = new Uri(appPath + "file11.avi");
            Files[11] = new Uri(appPath + "file12.avi");
            Files[12] = new Uri(appPath + "file13.avi");

            ShortDescriptions[00] = "Onion News Network";
            ShortDescriptions[01] = "Archer";
            ShortDescriptions[02] = "Beavis and Butthead";
            ShortDescriptions[03] = "Bored To Death";
            ShortDescriptions[04] = "Always Sunny In Philadelphia";
            ShortDescriptions[05] = "Law and Order";
            ShortDescriptions[06] = "Parks And Rec";
            ShortDescriptions[07] = "South Park";
            ShortDescriptions[08] = "The Office";
            ShortDescriptions[09] = "Lost";
            ShortDescriptions[10] = "The Good Wife";
            ShortDescriptions[11] = "Arrested Development";
            ShortDescriptions[12] = "Intervention";
        }




        private bool PowerStatus = false;
        private bool LockStatus = false;

               
        private Timer AutoLockTimer;

  

        private readonly KinectSensorChooser sensorChooser = new KinectSensorChooser();

        private Skeleton[] skeletons = new Skeleton[0];

        // skeleton gesture recognizer
        private GestureController gestureController;

        public MainWindow()
        {


            DataContext = this;

            InitializeComponent();

            // initialize the Kinect sensor manager
            KinectSensorManager = new KinectSensorManager();
            KinectSensorManager.KinectSensorChanged += this.KinectSensorChanged;

            // locate an available sensor
            sensorChooser.Start();

            // bind chooser's sensor value to the local sensor manager
            var kinectSensorBinding = new Binding("Kinect") { Source = this.sensorChooser };
            BindingOperations.SetBinding(this.KinectSensorManager, KinectSensorManager.KinectSensorProperty, kinectSensorBinding);


            VolumeBar.Minimum = 0;
            VolumeBar.Maximum = 100;
            VolumeBar.Value = 50;
            initializeFiles();
           ChangePlayerContent(1);

            AutoLockTimer = new Timer();
            AutoLockTimer.Elapsed += new ElapsedEventHandler(AutoLockEvent);
            AutoLockTimer.Interval = 1000 * AutoTimeDelay;
            AutoLockTimer.Start();

            MutedLabel.Visibility = Visibility.Hidden;

#if DEBUG

            GestureLabel.Visibility = Visibility.Visible;

     //     SetManualControls(true);           

#else

            GestureLabel.Visibility = Visibility.Hidden;
    //        SetManualControls(false);

#endif
            Power();
            ToggleLock();
            ToggleLock();

        }

       private void SetManualControls(bool toggle){

           Visibility vis;
           if (toggle)
           {
               vis = Visibility.Visible;
           }
           else
           {
               vis = Visibility.Hidden;
           }



           SwipeDownButton.Visibility = vis;
           SwipeRightButton.Visibility = vis;
           SwipeLeftButton.Visibility = vis;
           SwipeUpButton.Visibility = vis;
           SwipeDownButton.Visibility = vis;
           MenuButton.Visibility = vis;
           PowerButton.Visibility = vis;
           MuteButton.Visibility = vis;

        }

        #region Kinect Discovery & Setup

        private void KinectSensorChanged(object sender, KinectSensorManagerEventArgs<KinectSensor> args)
        {
            if (null != args.OldValue)
                UninitializeKinectServices(args.OldValue);

            if (null != args.NewValue)
                InitializeKinectServices(KinectSensorManager, args.NewValue);
        }

        /// <summary>
        /// Kinect enabled apps should customize which Kinect services it initializes here.
        /// </summary>
        /// <param name="kinectSensorManager"></param>
        /// <param name="sensor"></param>
        private void InitializeKinectServices(KinectSensorManager kinectSensorManager, KinectSensor sensor)
        {
            // Application should enable all streams first.

            // configure the color stream
            kinectSensorManager.ColorFormat = ColorImageFormat.RgbResolution640x480Fps30;
            kinectSensorManager.ColorStreamEnabled = true;

            // configure the depth stream
            kinectSensorManager.DepthStreamEnabled = true;

            kinectSensorManager.TransformSmoothParameters =
                new TransformSmoothParameters
                {
                    Smoothing = 0.5f,
                    Correction = 0.5f,
                    Prediction = 0.5f,
                    JitterRadius = 0.05f,
                    MaxDeviationRadius = 0.04f
                };

            // configure the skeleton stream
            sensor.SkeletonFrameReady += OnSkeletonFrameReady;
            kinectSensorManager.SkeletonStreamEnabled = true;

            // initialize the gesture recognizer
            gestureController = new GestureController();
            gestureController.GestureRecognized += OnGestureRecognized;

            kinectSensorManager.KinectSensorEnabled = true;

            if (!kinectSensorManager.KinectSensorAppConflict)
            {
                // addition configuration, as needed
            }

            SetManualControls(false);
            DisconnectedLabel.Visibility = Visibility.Hidden;
        }

        /// <summary>
        /// Kinect enabled apps should uninitialize all Kinect services that were initialized in InitializeKinectServices() here.
        /// </summary>
        /// <param name="sensor"></param>
        private void UninitializeKinectServices(KinectSensor sensor)
        {

            SetManualControls(true);
            DisconnectedLabel.Visibility = Visibility.Visible;
        }

        #endregion Kinect Discovery & Setup

        #region Properties

        public static readonly DependencyProperty KinectSensorManagerProperty =
            DependencyProperty.Register(
                "KinectSensorManager",
                typeof(KinectSensorManager),
                typeof(MainWindow),
                new PropertyMetadata(null));

        public KinectSensorManager KinectSensorManager
        {
            get { return (KinectSensorManager)GetValue(KinectSensorManagerProperty); }
            set { SetValue(KinectSensorManagerProperty, value); }
        }

        /// <summary>
        /// Gets or sets the last recognized gesture.
        /// </summary>
        private string _gesture;
        public String Gesture
        {
            get { return _gesture; }

            private set
            {
                if (_gesture == value)
                    return;

                _gesture = value;

                Debug.WriteLine("Gesture = " + _gesture);

                if (this.PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Gesture"));

                GestureLabel.Content = _gesture;

            }
        }
        #endregion Properties

        #region Events

        /// <summary>
        /// Event implementing INotifyPropertyChanged interface.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion Events

        #region Event Handlers

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">Gesture event arguments.</param>
        private void OnGestureRecognized(object sender, GestureEventArgs e)
        {
            Debug.WriteLine(e.GestureType);

            ResetTimeoutClock();
            
            switch (e.GestureType)
            {
                case GestureType.Menu:
                    Gesture = "Menu";
                    Power();
                    break;
                case GestureType.WaveRight:
                case GestureType.WaveLeft:
                    Gesture = "Wave";
                    ToggleLock();
                    break;
                case GestureType.JoinedHands:
                    Gesture = "Joined Hands";
                    ToggleMute();
                    break;
                case GestureType.SwipeRightUp:
                case GestureType.SwipeLeftUp:
                    Gesture = "Swipe Up";
                    ChannelUp();
                    break;
                case GestureType.SwipeRight:
                case GestureType.SwipeAcrossRight:
                    Gesture = "Swipe Right";
                    VolumeUp();
                    break;
                case GestureType.SwipeLeft:
                case GestureType.SwipeAcrossLeft:
                    Gesture = "Swipe Left";
                    VolumeDown();
                    break;
                case GestureType.SwipeLeftDown:
                case GestureType.SwipeRightDown:
                    Gesture = "Swipe Down";
                    ChannelDown();
                    break;
                case GestureType.ZoomIn:
                    Gesture = "Zoom In";
                    break;
                case GestureType.ZoomOut:
                    Gesture = "Zoom Out";
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;

                // resize the skeletons array if needed
                if (skeletons.Length != frame.SkeletonArrayLength)
                    skeletons = new Skeleton[frame.SkeletonArrayLength];

                // get the skeleton data
                frame.CopySkeletonDataTo(skeletons);

                foreach (var skeleton in skeletons)
                {
                    // skip the skeleton if it is not being tracked
                    if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
                        continue;

                    // update the gesture controller
                    gestureController.UpdateAllGestures(skeleton);
                }
            }
        }

        #endregion Event Handlers



        private void ChannelUp()
        {

            if (!LockStatus)
            {

                int newChannel = Int32.Parse(ChannelLabel.Content.ToString()) + 1;
                if (newChannel > MaxChannel)
                    newChannel = 1;
                ChannelLabel.Content = newChannel;

                ChangePlayerContent(newChannel);
    
            }
        }

        private void ChannelDown()
        {

            if (!LockStatus)
            {
                int newChannel = Int32.Parse(ChannelLabel.Content.ToString()) - 1;
                if (newChannel == 0)
                    newChannel = MaxChannel;
                ChannelLabel.Content = newChannel;

                ChangePlayerContent(newChannel);
            }
        }
        private void VolumeUp()
        {

            if (!LockStatus)
            {
                if (VolumeBar.Value > VolumeBar.Maximum - VolumeIncrement)
                    VolumeBar.Value = VolumeBar.Maximum;
                else VolumeBar.Value += VolumeIncrement;
                Player.Volume = VolumeBar.Value / VolumeBar.Maximum;

                if(Player.IsMuted)
                    ToggleMute();
            }

           


        }

        private void VolumeDown()
        {

            if (!LockStatus)
            {
                if (VolumeBar.Value < VolumeBar.Minimum + VolumeIncrement)
                    VolumeBar.Value = VolumeBar.Minimum;
                else VolumeBar.Value -= VolumeIncrement;
                Player.Volume = VolumeBar.Value / VolumeBar.Maximum;
              //  Player.IsMuted = false;
            }
        }

        private void Power()
        {
           
            Visibility vis;
            if (!PowerStatus)
            {
                vis = Visibility.Visible;

            }
            else
            {
                vis = Visibility.Hidden;

            }

            VolumeBar.Visibility = vis;
            VolumeLabel.Visibility = vis;
            ChannelLabel.Visibility = vis;
            Player.Visibility = vis;
            
          
            Player.IsMuted = PowerStatus;

          
                   
            ToggleLock();
            LockStatus = PowerStatus;     

            PowerStatus = !PowerStatus;
        }

        private void ToggleLock(){
             
             Visibility vis;
             if (LockStatus)
             {
                 vis = Visibility.Visible;
             }
             else
             {
                 vis = Visibility.Hidden;
             }

             VolumeBar.Visibility = vis;
             VolumeLabel.Visibility = vis;
             ChannelLabel.Visibility = vis;
             ClockLabel.Visibility = vis;
             ActiveContentLabel_Plus4.Visibility = vis;
             ActiveContentLabel_Plus3.Visibility = vis;
             ActiveContentLabel_Plus2.Visibility = vis;
             ActiveContentLabel_Plus1.Visibility = vis;
             ActiveContentLabel.Visibility = vis;
             ActiveContentLabel_Minus1.Visibility = vis;
             ActiveContentLabel_Minus2.Visibility = vis;
             ActiveContentLabel_Minus3.Visibility = vis;
             ActiveContentLabel_Minus4.Visibility = vis;


             ClockLabel.Content = DateTime.Now.TimeOfDay.Hours + ":" + DateTime.Now.TimeOfDay.Minutes.ToString("00"); ;

 

             LockStatus = !LockStatus;

        }



        private void ToggleMute()
        {
            if (Player.IsMuted)
                MutedLabel.Visibility = Visibility.Hidden;
            else MutedLabel.Visibility = Visibility.Visible;

            Player.IsMuted = !Player.IsMuted;
             
        }

        private void ChangePlayerContent(int channel)
        {

            RotateChannelGuide(channel);


            try
            {

                TimeSpan pos = Player.Position;

                Player.Source = Files[channel - 1];

                Player.Position = pos;
                Player.Play();

                
            }
            catch (Exception e)
            {
             //   Gesture = "player error";

            }
        }

        private void RotateChannelGuide(int channel)
        {
            ActiveContentLabel_Plus4.Content = ShortDescriptions[ChannelWrapHelper(channel, 4)];
            ActiveContentLabel_Plus3.Content = ShortDescriptions[ChannelWrapHelper(channel, 3)];
            ActiveContentLabel_Plus2.Content = ShortDescriptions[ChannelWrapHelper(channel, 2)];
            ActiveContentLabel_Plus1.Content = ShortDescriptions[ChannelWrapHelper(channel, 1)];
            ActiveContentLabel.Content = ShortDescriptions[ChannelWrapHelper(channel, 0)];
            ActiveContentLabel_Minus1.Content = ShortDescriptions[ChannelWrapHelper(channel, -1)];
            ActiveContentLabel_Minus2.Content = ShortDescriptions[ChannelWrapHelper(channel, -2)];
            ActiveContentLabel_Minus3.Content = ShortDescriptions[ChannelWrapHelper(channel, -3)];
            ActiveContentLabel_Minus4.Content = ShortDescriptions[ChannelWrapHelper(channel, -4)];
        }

        private int ChannelWrapHelper(int channel, int offset)
        {

            if (channel + offset - 1 < 0)
            {
                return MaxChannel + offset + channel - 1;
            }
            else if (channel + offset > MaxChannel)
            {
                return channel + offset - MaxChannel - 1;
            }
            else return channel + offset - 1;
        }




        private void ResetTimeoutClock()
        {
            AutoLockTimer.Stop();
            AutoLockTimer.Start();
        }

        private void SwipeDownButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            ChannelDown();
        }

        private void PowerButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            Power();
        }

        private void MenuButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            ToggleLock();
        }

        private void SwipeRightButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            VolumeUp();
        }

        private void SwipeLeftButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            VolumeDown();
        }

        private void SwipeUpButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            ChannelUp();
        }

        private void MuteButton_Click(object sender, RoutedEventArgs e)
        {
            ResetTimeoutClock();
            ToggleMute();
        }

        public void AutoLockEvent(object source, ElapsedEventArgs e)
        {

            System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
            {
                if (!LockStatus)
                    ToggleLock();
            });

         
        }

        private void VolumeBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {

        }
    }
}